#pragma once

#include <iostream>
#include <memory>
#include <unordered_map>

#include "Epoller.hpp"
#include "Connection.hpp"

class Reactor
{
    static const int gnum = 64;

public:
    Reactor()
        : _epoller(std::make_unique<Epoller>()), _isrunning(false)
    {
    }

    void AddConnection(int fd, uint32_t events, const InetAddr& addr, int type)
    {
        // 1. 构建一个新的Connection
        Connection* conn = new Connection(fd);
        conn->SetEvents(events);
        conn->SetConnectionType(type);
        conn->SetAddr(addr);
        conn->SetReactor(this);

        if(conn->Type() == ListenConnection)
        {
            conn->RegisterHandler(_OnConnect, nullptr, nullptr);
        }
        else
        {
            conn->RegisterHandler(_OnRecver, _OnSender, _OnExcepter);
        }

        LOG(INFO, "RegisterHandler success, sockfd: %d\n", fd);

        // 2. 将新连接托管给内核
        if(!_epoller->AddEvent(conn->Sockfd(), conn->Events()))
            return;
        
        // 3. 将新连接添加进Reactor的连接管理集中
        _connections.insert(std::make_pair(fd, conn));
    }

    void EnableConnectionReadWrite(int sockfd, bool readable, bool writeable)
    {
        if(!IsConnectionExists(sockfd))
        {
            return;
        }

        // 设置连接的events属性
        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _connections[sockfd]->SetEvents(events);

        // 设置epoller对于连接的事件关心
        _epoller->ModEvent(_connections[sockfd]->Sockfd(), _connections[sockfd]->Events());
    }

    void DelConnection(int sockfd)      // 删除连接
    {
        if(!IsConnectionExists(sockfd))
        {
            return;
        }
        LOG(INFO, "sockfd %d quit, 服务器释放其所有资源\n", sockfd);

        // 取消内核对其的关心
        EnableConnectionReadWrite(sockfd, false, false);
        _epoller->DelEvent(sockfd);
        // 关闭连接
        _connections[sockfd]->Close();
        // 删除资源
        delete _connections[sockfd];
        // 移除管理
        _connections.erase(sockfd);
    }

    void LoopOnce(int timeout)
    {
        // revs[]中都是条件就绪的文件描述符，可以通过fd得到具体是哪个就绪了，通过events可以知道具体是什么事件就绪了
        int n = _epoller->Wait(_revs, gnum, timeout);
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            if (revents & EPOLLERR) // 如果出现错误,都交给读事件和写事件处理
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);
            // 事件派发
            if (revents & EPOLLIN)
            {
                if (IsConnectionExists(sockfd) && _connections[sockfd]->_handler_recver)
                    _connections[sockfd]->_handler_recver(_connections[sockfd]);
                
                LOG(DEBUG, "sockfd: %d use Recver function\n", sockfd);
            }
            if (revents & EPOLLOUT)
            {
                if (IsConnectionExists(sockfd) && _connections[sockfd]->_handler_sender)
                    _connections[sockfd]->_handler_sender(_connections[sockfd]);
                
                LOG(DEBUG, "sockfd: %d use Sender function\n", sockfd);
            }
        }
    }

    bool IsConnectionExists(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }

    void SetOnConnect(handler_t OnConnect)
    {
        _OnConnect = OnConnect;
    }

    void SetOnNormalHandler(handler_t recver, handler_t sender, handler_t excepter)
    {
        _OnRecver = recver;
        _OnSender = sender;
        _OnExcepter = excepter;
    }

    void Dispatcher()
    {
        int timeout = -1;   // 阻塞等待获取连接
        _isrunning = true;
        while(_isrunning)
        {
            LoopOnce(timeout);

            PrintDebug();
        }
        _isrunning = false;
    }

    void PrintDebug()
    {
        std::string fdlist;
        for (auto &conn : _connections)
        {
            fdlist += std::to_string(conn.second->Sockfd()) + " ";
        }
        LOG(DEBUG, "epoll管理的fd列表: %s\n", fdlist.c_str());
    }

private:
    std::unordered_map<int, Connection *> _connections;
    std::unique_ptr<Multiplex> _epoller;
    struct epoll_event _revs[gnum];
    bool _isrunning;

    // 方法集，用来给连接注入IO方法，由上层传入
    // 1. 用于处理新连接
    handler_t _OnConnect;
    // 2. 处理普通的sockfd，主要是IO处理
    handler_t _OnRecver;
    handler_t _OnSender;
    handler_t _OnExcepter;
};